package com.htfyun.ft.fragment.factory;

import android.content.Context;
import android.graphics.Color;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.os.Bundle;
import android.os.Message;
import android.text.TextUtils;
import android.view.View;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.TextView;

import com.htfyun.ft.R;
import com.htfyun.ft.common.FTUtils;
import com.htfyun.ft.utils.DebugLog;
import com.htfyun.ft.utils.FileReadWrite;
import com.htfyun.ft.utils.executor.AppExecutors;
import com.htfyun.serialport.utils.UsefulUtil;

import java.io.File;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Locale;

import androidx.annotation.Nullable;

public class FragmentProximitySensor extends FactoryBaseFragment implements View.OnClickListener {

    private TextView txtReportValue;
    private TextView txtRawValue;
    private TextView txtDesc;

    private LinearLayout layoutTxtReportValue;

    private Button btnSampleStart;

    private SensorManager sensorManager;
    private MySensorListener sensorEventListener;
    private Sensor proximitySensor;

    private Context mContext;

    private final static int DEFAULT_SAMPLE_TIME = 12;//12s
    private int countdown = DEFAULT_SAMPLE_TIME;

    private final static String PATH_RAW_VALUE = "/sys/class/htfyun-ps/sensor_value";
    private final static String PATH_SAMPLE_30CM = "/sys/class/htfyun-ps/sample_30cm";

    private List<Integer> distanceList = null;

    private volatile boolean isInvisible =  true;

    @Override
    protected int getLayoutRes() {
        return R.layout.fragment_factory_proximity_sensor;
    }

    @Override
    protected void onInitView(@Nullable Bundle savedInstanceState) {
        super.onInitView(savedInstanceState);

        mContext = getContext();

        txtReportValue = (TextView) findViewById(R.id.txtReportValue);
        txtRawValue = (TextView) findViewById(R.id.txtRawValue);
        txtDesc = (TextView) findViewById(R.id.txtDesc);
        txtDesc.setText(getString(R.string.proximity_read_sample_30cm, FileReadWrite.readFileByLines(PATH_SAMPLE_30CM)));

        sensorManager = mContext.getSystemService(SensorManager.class);
        proximitySensor = sensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY);

        sensorEventListener = new MySensorListener();

        setBtnPassVisibility(View.GONE);

        btnSampleStart = (Button) findViewById(R.id.btnSampleStart);
        if (btnSampleStart != null) {
            btnSampleStart.setOnClickListener(this);
        }

        layoutTxtReportValue = (LinearLayout) findViewById(R.id.layoutTxtReportValue);
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.btnSampleStart:
                unregisterListener();// 不去监听sensor
                btnSampleStart.setEnabled(false);
                countdown = DEFAULT_SAMPLE_TIME;
                txtReportValue.setText("");
                txtRawValue.setText("");

                if (distanceList != null) {
                    distanceList.clear();
                    distanceList = null;
                }

                layoutTxtReportValue.setVisibility(View.GONE);

                if (!isInvisible) getHandler().sendEmptyMessage(MSG_COUNT_DOWN);
                AppExecutors.runOnIoThread(new CommandRunnable(CommandAttr.start));

                break;
        }

    }

    @Override
    protected void onVisible() {
        super.onVisible();

        isInvisible = false;

        if (distanceList != null) {
            distanceList.clear();
            distanceList = null;
        }
        txtReportValue.setText("");
        txtRawValue.setText("");
        layoutTxtReportValue.setVisibility(View.GONE);
        btnSampleStart.setEnabled(true);

        registerListener();
        if (!isInvisible) getHandler().sendEmptyMessage(MSG_READ_RAW);
    }

    @Override
    protected void onInvisible() {
        super.onInvisible();

        isInvisible = true;

        unregisterListener();

        getHandler().removeMessages(MSG_READ_RAW_VALUE_OVER);
        getHandler().removeMessages(MSG_READ_SAMPLE_30CM_VALUE_OVER);
        getHandler().removeMessages(MSG_READ_RAW);
        getHandler().removeMessages(MSG_COUNT_DOWN);

    }

    private void setLayoutTxtReportValueAllBlue() {
        int childCount = layoutTxtReportValue.getChildCount();
        for (int i = 0; i < childCount; i++) {
            View child = layoutTxtReportValue.getChildAt(i);
            if (child instanceof TextView) {
                ((TextView)child).setTextColor(Color.BLUE);
            }
        }
    }
    private void setLayoutTxtReportValueGreenColor(String tag) {
        int childCount = layoutTxtReportValue.getChildCount();
        for (int i = 0; i < childCount; i++) {
            View child = layoutTxtReportValue.getChildAt(i);
            if (child instanceof TextView && child.getTag() != null && child.getTag().equals(tag)) {
                ((TextView)child).setTextColor(Color.GREEN);
            }
        }
    }

    private volatile boolean isRegistered = false;

    private synchronized void registerListener() {
        if (isRegistered) {
            return;
        }
        isRegistered = true;

        sensorManager.registerListener(sensorEventListener, proximitySensor, SensorManager.SENSOR_DELAY_NORMAL);

        sensorEventListener.resetDiscardCount();
        DebugLog.e("registerListener");
    }

    private synchronized void unregisterListener() {
        if (!isRegistered) {
            return;
        }
        isRegistered = false;
        sensorManager.unregisterListener(sensorEventListener);

        DebugLog.e("unregisterListener");

    }


    private void updateTxtReportValue(int value, int discardCount) {
        String text = txtReportValue.getText().toString();
        if (text.length() > 200) {
            text = "";
        }

        if (discardCount >= 0) {

            txtReportValue.setText(getString(R.string.proximity_sensor_report_value_discard, text, value, discardCount));

        } else {

            txtReportValue.setText(getString(R.string.proximity_sensor_report_value, text, value));
        }


    }

    private void updateTxtRawValue(int value) {
        String text = txtRawValue.getText().toString();
        if (text.length() > 200) {
            text = "";
        }

        txtRawValue.setText(getString(R.string.proximity_sensor_raw_value, text, value));

        save(String.valueOf(value));

    }

    private void updateCountDown() {
        countdown--;
        txtDesc.setText(getString(R.string.proximity_sensor_desc_sample, DEFAULT_SAMPLE_TIME, countdown));

        if (countdown > 0) {
            if (!isInvisible) getHandler().sendEmptyMessageDelayed(MSG_COUNT_DOWN, PERIOD_COUNT_DOWN);
        } else {
            AppExecutors.runOnIoThread(new CommandRunnable(CommandAttr.stop));
            btnSampleStart.setEnabled(true);
        }

    }

    private void readSample30cmOver(int value) {

        if (value <= 0) {
            txtDesc.setText(getString(R.string.proximity_error_read_sample_30cm_over, value));
            return;
        }

        txtDesc.setText(getString(R.string.proximity_read_sample_30cm_over, value));

        registerListener();

        layoutTxtReportValue.setVisibility(View.VISIBLE);
        setLayoutTxtReportValueAllBlue();

        if (distanceList != null) {
            distanceList.clear();
            distanceList = null;
        }
        distanceList = new ArrayList<>();
        distanceList.add(0);
        distanceList.add(1);
        distanceList.add(30);
        distanceList.add(40);

    }

    private Runnable readRawValueRunnable = new Runnable() {
        @Override
        public void run() {

            String valueString = FileReadWrite.readFileByLines(PATH_RAW_VALUE);

            if (TextUtils.isEmpty(valueString)) {
                return;
            }

            if (UsefulUtil.isNumeric(valueString)) {
                int value = Integer.decode(valueString);
                if (!isInvisible) getHandler().obtainMessage(MSG_READ_RAW_VALUE_OVER, value, 0).sendToTarget();
            }
        }
    };

    private Runnable readSample30cmValueRunnable = new Runnable() {
        @Override
        public void run() {
            String valueString = FileReadWrite.readFileByLines(PATH_SAMPLE_30CM);
            if (TextUtils.isEmpty(valueString)) {
                return;
            }
            if (UsefulUtil.isNumeric(valueString)) {
                int value = Integer.decode(valueString);
                if (!isInvisible) getHandler().obtainMessage(MSG_READ_SAMPLE_30CM_VALUE_OVER, value, 0).sendToTarget();
            }
        }
    };

    private enum CommandAttr {
        start("start"),
        stop("stop"),
        ;
        final String cmd;

        private CommandAttr(String cmd) {
            this.cmd = cmd;
        }

        public String getCmd() {
            return cmd;
        }
    }


    private final class CommandRunnable implements Runnable {


        //start: 开启采样
        //stop: 停止采样
        private final CommandAttr command;

        public CommandRunnable(CommandAttr cmd) {
            command = cmd;
        }
        @Override
        public void run() {
            FileReadWrite.writeStringToFile(PATH_SAMPLE_30CM, command.getCmd());

            if (command == CommandAttr.stop) {
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

                readSample30cmValueRunnable.run();
            }

        }
    }


    private final class MySensorListener implements SensorEventListener {

        private final int DISCARD_COUNT = 3;
        private int discardCount ;
        @Override
        public void onSensorChanged(SensorEvent event) {

            if (event.sensor.getType() != Sensor.TYPE_PROXIMITY) {
                return;
            }

            int value = (int)event.values[0];


            discardCount--;
            updateTxtReportValue(value, discardCount);

            if (discardCount >= 0) {

                return;
            }


            if (distanceList != null) {
                setLayoutTxtReportValueGreenColor(String.valueOf(value));
                distanceList.remove(Integer.valueOf(value));
                if (distanceList.isEmpty()) {
                    delayAutoPass();
                }
            }

        }

        @Override
        public void onAccuracyChanged(Sensor sensor, int accuracy) {

        }

        public void resetDiscardCount() {
            this.discardCount = DISCARD_COUNT;
        }
    }

    private final static int MSG_READ_RAW_VALUE_OVER = 100;
    private final static int MSG_READ_SAMPLE_30CM_VALUE_OVER = 101;
    private final static int MSG_READ_RAW = 1000;
    private final static int PERIOD_READ_RAW = 2000;

    private final static int MSG_COUNT_DOWN = 10001;
    private final static int PERIOD_COUNT_DOWN = 1000;

    @Override
    protected void handleMessage(Message msg) {
        switch (msg.what) {
            case MSG_READ_RAW_VALUE_OVER:
                updateTxtRawValue(msg.arg1);
                break;
            case MSG_READ_SAMPLE_30CM_VALUE_OVER:
                readSample30cmOver(msg.arg1);
                break;
            case MSG_READ_RAW:
                AppExecutors.runOnIoThread(readRawValueRunnable);
                if (!isInvisible) getHandler().sendEmptyMessageDelayed(msg.what, PERIOD_READ_RAW);
                break;

            case MSG_COUNT_DOWN:
                updateCountDown();
                break;
        }
    }

    //////////////////////////////////////
    private final static String DEBUG_DIR = FTUtils.getFTStorageDirectory()
            + File.separator + "psensor";


    public static String getDebugDir() {
        File file_dir = new File(DEBUG_DIR);
        if (!(file_dir.exists())) {
            file_dir.mkdirs();
        }

        return file_dir.getAbsolutePath();
    }

    private static String getFileName() {

        return getDebugDir() + File.separator + now2String() + ".log";

    }

    private static String fileName = null;

    private static void save(String string) {

        if (fileName == null) {
            fileName = getFileName();
        }

        String appendString = now2String() + " : " + string + "\n";

        FileReadWrite.writeAppendFile(fileName, appendString);


    }

    private static final ThreadLocal<SimpleDateFormat> SDF_THREAD_LOCAL = new ThreadLocal<>();

    private static SimpleDateFormat getDefaultFormat() {
        SimpleDateFormat simpleDateFormat = SDF_THREAD_LOCAL.get();
        if (simpleDateFormat == null) {
            simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd_HH-mm-ss.SSS", Locale.getDefault());
            SDF_THREAD_LOCAL.set(simpleDateFormat);
        }
        return simpleDateFormat;
    }

    private static String now2String() {
        return getDefaultFormat().format(new Date());
    }

}
